/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "hci_transport.h"
#include "nfa_base.h"
#include "nfc_log_api.h"
#include "nci_data.h"
#include "nci_utils.h"
#include "hci_defs.h"
#include "hci_cmd.h"
#include "data_int.h"
#include "nci_feature.h"

/**
 * @brief HCI传输层，管理往HCI通道发送的数据，分发HCI通道上报的数据
 */
#if IS_FEATURE_ON(NCI_FEATURE_HCI)

#define MAX_HCI_HCP_EVENT_HANDLER (5)

typedef struct {
    uint8_t pipe;
    tHCI_HCP_EVENT_HANDLE handle;
} tHCI_HCP_EVENT_HANDLE_TABLE;

static tMUTEX g_hci_rsp_lock = MUTEX_INIT_VAL("hci_rsp");
// protect by g_hci_rsp_lock
static tNCI_BUF g_hci_rsp_buf;
static uint8_t g_pending_hci_cmd_pipe;
// protect by g_hci_rsp_lock end
static tMUTEX g_hcp_event_handle_lock = MUTEX_INIT_VAL("hcp_event");
// protect by g_hcp_event_handle_lock
static tHCI_HCP_EVENT_HANDLE_TABLE *g_hcp_event_handle_tables = NULL;
// protect by g_hcp_event_handle_lock end
static void hci_data_handler(uint8_t conn_id, const uint8_t *data, uint16_t data_len);
static void hci_handle_remote_event(uint8_t pipe, const uint8_t *data, uint16_t data_len);
static void hci_handle_remote_rsp(uint8_t pipe, const uint8_t *data, uint16_t data_len);

/**
 * @brief 初始化hci transport层
 * @note 初始化transport层需要的内存和锁，向data模块注册HCI data通道的数据回调
 * @return 成功时返回NCI_STATUS_OK
 */
tNCI_STATUS hci_transport_init(void) {
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    NFCLOG_D("enter");
    g_hcp_event_handle_tables = osi_malloc(MAX_HCI_HCP_EVENT_HANDLER * sizeof(tHCI_HCP_EVENT_HANDLE_TABLE));
    if (!g_hcp_event_handle_tables) {
        NFCLOG_E("malloc for hcp event handle tables failed");
        status = NCI_STATUS_EXT_ALLOC_FAILED;
        goto clean;
    }
    if (!osi_memset_s(g_hcp_event_handle_tables, MAX_HCI_HCP_EVENT_HANDLER * sizeof(tHCI_HCP_EVENT_HANDLE_TABLE), 0,
        MAX_HCI_HCP_EVENT_HANDLER * sizeof(tHCI_HCP_EVENT_HANDLE_TABLE))) {
        NFCLOG_E("memset failed");
        goto clean;
    }
    tNFC_STATUS nfc_status = osi_mutex_init(&g_hci_rsp_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("init mutex for hci transport failed");
        status = NCI_STATUS_EXT_GET_LOCK_FAILED;
        goto clean;
    }
    nfc_status = osi_mutex_init(&g_hcp_event_handle_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("init mutex for hci hcp event handle failed");
        status = NCI_STATUS_EXT_GET_LOCK_FAILED;
        goto clean;
    }
    NFCLOG_D("register data callback for hci");
    status = data_register_cback(NCI_DATA_CHANNEL_HCI, hci_data_handler);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("register hci data cb failed. ret:%d", status);
        goto clean;
    }
    return status;
clean:
    osi_mutex_deinit(&g_hci_rsp_lock);
    osi_mutex_deinit(&g_hcp_event_handle_lock);
    if (g_hcp_event_handle_tables) {
        osi_free(g_hcp_event_handle_tables);
        g_hcp_event_handle_tables = NULL;
    }
    return status;
}

/**
 * @brief hci transport层去初始化
 * @note 释放所有内存和锁，注销向data模块注册的数据回调
 * @return 成功时返回NCI_STATUS_OK
 */
tNCI_STATUS hci_transport_deinit(void) {
    tNCI_STATUS status;
    tNFC_STATUS nfc_status;
    nfc_status = osi_mutex_lock(&g_hci_rsp_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("mutex for hci transport is released");
        goto release_hcp_event_handle_tables;
    }
    if (g_hci_rsp_buf.data) {
        osi_free(g_hci_rsp_buf.data);
        g_hci_rsp_buf.cap = 0;
        g_hci_rsp_buf.len = 0;
        g_hci_rsp_buf.data = NULL;
    }
    nfc_status = osi_mutex_unlock(&g_hci_rsp_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("mutex for hci transport is released");
        goto release_hcp_event_handle_tables;
    }
    nfc_status = osi_mutex_deinit(&g_hci_rsp_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("deinit mutex for hci transport failed");
    }
release_hcp_event_handle_tables:
    nfc_status = osi_mutex_lock(&g_hcp_event_handle_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("mutex for hcp event handle is released");
        goto unregister_cback;
    }
    osi_free(g_hcp_event_handle_tables);
    g_hcp_event_handle_tables = NULL;
    nfc_status = osi_mutex_unlock(&g_hcp_event_handle_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("mutex for hcp event handle is released");
        goto unregister_cback;
    }
    nfc_status = osi_mutex_deinit(&g_hcp_event_handle_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("deinit mutex for hcp event handle failed");
    }
unregister_cback:
    status = data_unregister_cback(NCI_DATA_CHANNEL_HCI, hci_data_handler);
    if (NCI_STATUS_OK != status) {
        NFCLOG_W("unregister hci data cb failed");
    }
    return status;
}

/**
 * @brief 注册某个pipe的hci event回调
 * @param pipe   关注的pipe
 * @param handle 回调方法
 * @return 成功时返回NCI_STATUS_OK
 */
tNCI_STATUS hci_transport_register_pipe_event_handler(uint8_t pipe, tHCI_HCP_EVENT_HANDLE handle) {
    int i = 0;
    tNCI_STATUS status = NCI_STATUS_OK;
    NFCLOG_D("%sregister hcp event for pipe:%02X", (NULL == handle) ? "de" : "", pipe);
    tNFC_STATUS nfc_status = osi_mutex_lock(&g_hcp_event_handle_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("mutex for hcp event handle is released");
        status = NCI_STATUS_EXT_GET_LOCK_FAILED;
        goto exit;
    }
    // 检查是否已经注册过call back
    for (i = 0; i < MAX_HCI_HCP_EVENT_HANDLER; ++i) {
        if (pipe == g_hcp_event_handle_tables[i].pipe) {
            break;
        }
    }
    if (i < MAX_HCI_HCP_EVENT_HANDLER) {
        g_hcp_event_handle_tables[i].handle = handle;
        if (NULL == handle) {
            // 如果是空的handle就释放当前槽位
            g_hcp_event_handle_tables[i].pipe = 0;
        }
        goto unlock;
    }
    if (NULL == handle) {
        goto unlock;
    }
    // 寻找空闲的call back槽位
    for (i = 0; i < MAX_HCI_HCP_EVENT_HANDLER; ++i) {
        if (0 == g_hcp_event_handle_tables[i].pipe) {
            break;
        }
    }
    if (i < MAX_HCI_HCP_EVENT_HANDLER) {
        g_hcp_event_handle_tables[i].pipe = pipe;
        g_hcp_event_handle_tables[i].handle = handle;
    } else {
        NFCLOG_E("no hcp event callback slot avaliable");
        status = NCI_STATUS_EXT_CALLBACK_FULL;
    }
unlock:
    nfc_status = osi_mutex_unlock(&g_hcp_event_handle_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("mutex for hcp event handle is released");
    }
exit:
    return status;
}

/**
 * @brief 处理HCI data通道收到的数据，并按照hcp类型分发到内部对应处理接口
 * @param conn_id   data通道id
 * @param data      收到的data
 * @param data_len  收到的data长度
 */
static void hci_data_handler(uint8_t conn_id, const uint8_t *data, uint16_t data_len) {
    if (NCI_DATA_CHANNEL_HCI != conn_id) {
        NFCLOG_W("data not from hci data conn");
        return;
    }
    NFCLOG_D("hci recv data len:%d", data_len);
    if (data_len < 2) {
        NFCLOG_W("invalid hci packet");
        return;
    }

    switch ((data[1] & HCI_HCP_TYPE_MASK) >> HCI_HCP_TYPE_OFFSET) {
    case HCI_HCP_TYPE_CMD:
        hci_handle_remote_cmd(data[0] & HCI_PIPE_MASK, data[1] & HCI_INS_MASK, data + 2, data_len - 2);
        break;
    case HCI_HCP_TYPE_RSP:
        hci_handle_remote_rsp(data[0] & HCI_PIPE_MASK, data + 1, data_len - 1);
        break;
    case HCI_HCP_TYPE_EVENT:
        hci_handle_remote_event(data[0] & HCI_PIPE_MASK, data + 1, data_len - 1);
        break;
    default:
        NFCLOG_E("unknown hcp packet type");
        break;
    }
}

/**
 * @brief 发送hcp包
 * @note 异步发送接口，不会等待回复，如果hci data通道credits不足会阻塞等待
 * @param pipe_id  要往哪个pipe发送数据
 * @param ins_type hcp包的类型
 * @param ins      hcp包的指令
 * @param data_len hcp包所带的数据长度
 * @param data     hcp包所带的数据
 * @return 成功时返回NCI_STATUS_OK
 */
tNCI_STATUS hci_send_hcp_message_async(uint8_t pipe_id, uint8_t ins_type, uint8_t ins,
                                     uint16_t data_len, const uint8_t *data) {
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *cmd = alloc_nci_buf(0);
    if (NULL == cmd) {
        NFCLOG_E("malloc failed");
        status = NCI_STATUS_EXT_ALLOC_FAILED;
        goto exit;
    }

    UINT8_TO_BUF(cmd, HCI_HCP_CHAINING_BIT | (pipe_id & HCI_PIPE_MASK));
    UINT8_TO_BUF(cmd, (ins_type << HCI_HCP_TYPE_OFFSET) | (ins & HCI_INS_MASK));
    ARRAY_TO_BUF(cmd, data, data_len);
    status = nci_data_channel_transmit_async(NCI_DATA_CHANNEL_HCI, cmd);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("%s send hci packet failed", __func__);
    }
    free_nci_buf(cmd);
exit:
    return status;
}

/**
 * @brief 发送hcp cmd并等待rsp
 * @note  rsp_data需要由调用者进行释放
 * @param pipe_id   要操作的pipe
 * @param ins_type  hcp数据包类型，此方法只支持HCI_HCP_TYPE_CMD类型
 * @param ins       要发送的指令
 * @param data_len  要发送的指令参数长度
 * @param data      要发送的指令参数
 * @param rsp_len   回复的数据长度
 * @param rsp_data  回复的数据，包含HCP header和data
 * @return 成功时返回NCI_STATUS_OK，不会对rsp code做处理，指令有响应即会返回成功
 */
tNCI_STATUS hci_process_hcp_message(uint8_t pipe_id, uint8_t ins_type, uint8_t ins,
                                     uint16_t data_len, const uint8_t *data,
                                     uint16_t *rsp_len, uint8_t **rsp_data) {
    tNCI_STATUS ret;
    tNFC_STATUS nfc_status;
    tNCI_BUF *cmd = NULL;
    if ((NULL == rsp_len) || (NULL == rsp_data)) {
        NFCLOG_E("invalid param!! data:%d rsp_len:%d rsp_data:%d", !!data, !!rsp_len, !!rsp_data);
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    *rsp_len = 0;
    cmd = alloc_nci_buf(0);
    if (NULL == cmd) {
        NFCLOG_E("malloc failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto exit;
    }
    UINT8_TO_BUF(cmd, HCI_HCP_CHAINING_BIT | (pipe_id & HCI_PIPE_MASK));
    UINT8_TO_BUF(cmd, (ins_type << HCI_HCP_TYPE_OFFSET) | (ins & HCI_INS_MASK));
    ARRAY_TO_BUF(cmd, data, data_len);
    nfc_status = osi_mutex_lock(&g_hci_rsp_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("mutex for hci transport is released");
        ret = NCI_STATUS_EXT_GET_LOCK_FAILED;
        goto exit;
    }
    ret = nci_data_channel_transmit_async(NCI_DATA_CHANNEL_HCI, cmd);
    if (NCI_STATUS_OK != ret) {
        NFCLOG_E("nci data transmit err. ret:%d", ret);
        goto unlock;
    }
    g_pending_hci_cmd_pipe = pipe_id;
    nfc_status = osi_mutex_wait(&g_hci_rsp_lock, HCI_CMD_TIMEOUT_MS);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("wait for hci rsp failed. ret:%d", nfc_status);
        ret = NCI_STATUS_EXT_TIMEOUT;
        goto unlock;
    }
    *rsp_len = g_hci_rsp_buf.len;
    *rsp_data = g_hci_rsp_buf.data;
    // g_hci_rsp_buf.data直接传递给调用者，由调用者进行释放
    g_hci_rsp_buf.data = NULL;
    g_hci_rsp_buf.cap = g_hci_rsp_buf.len = 0;
    ret = NCI_STATUS_OK;
unlock:
    if (NFC_STATUS_OK != osi_mutex_unlock(&g_hci_rsp_lock)) {
        NFCLOG_E("mutex for hci transport is released");
    }
exit:
    if (cmd) {
        free_nci_buf(cmd);
        cmd = NULL;
    }
    return ret;
}

/**
 * @brief 处理hci event，根据pipe分发到对应的回调
 * @param pipe     hci event来源pipe
 * @param data     hci event的内容
 * @param data_len hci event内容长度
 */
static void hci_handle_remote_event(uint8_t pipe, const uint8_t *data, uint16_t data_len) {
    tHCI_HCP_EVENT_HANDLE handle = NULL;
    tNFC_STATUS nfc_status = osi_mutex_lock(&g_hcp_event_handle_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("mutex for hci transport is released");
        return;
    }
    for(int i = 0; i < MAX_HCI_HCP_EVENT_HANDLER; ++i) {
        if (pipe == g_hcp_event_handle_tables[i].pipe) {
            handle = g_hcp_event_handle_tables[i].handle;
            break;
        }
    }
    nfc_status = osi_mutex_unlock(&g_hcp_event_handle_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("mutex for hci transport is released");
    }
    if (NULL == handle) {
        NFCLOG_W("no callback for pipe:%02X event", pipe);
        return;
    }
    handle(pipe, data, data_len);
}

/**
 * @brief 处理和分发hci rsp数据
 * @param pipe rsp从哪个pipe上报
 * @param data rsp的内容，包含hcp header和data
 * @param data_len rsp的长度
 */
static void hci_handle_remote_rsp(uint8_t pipe, const uint8_t *data, uint16_t data_len) {
    if (NFC_STATUS_OK != osi_mutex_lock(&g_hci_rsp_lock)) {
        NFCLOG_E("mutex for hci transport is released");
        return;
    }
    // 检查rsp的来源是否与cmd发下去的同一个pipe
    if (pipe != g_pending_hci_cmd_pipe) {
        NFCLOG_W("rsp not for last cmd. pending pipe:%02X current pipe:%02X", g_pending_hci_cmd_pipe, pipe);
        goto exit;
    }
    if (g_hci_rsp_buf.data) {
        NFCLOG_W("drop not handled rsp packet");
        osi_free(g_hci_rsp_buf.data);
        g_hci_rsp_buf.data = 0;
    }
    g_hci_rsp_buf.data = osi_malloc(data_len);
    if (!g_hci_rsp_buf.data) {
        NFCLOG_E("malloc failed");
        goto exit;
    }
    if (!osi_memcpy_s(g_hci_rsp_buf.data, data_len, data, data_len)) {
        NFCLOG_E("memcpy failed");
        osi_free(g_hci_rsp_buf.data);
        g_hci_rsp_buf.data = 0;
        goto exit;
    }
    g_hci_rsp_buf.cap = g_hci_rsp_buf.len = data_len;
    if (NFC_STATUS_OK != osi_mutex_notify(&g_hci_rsp_lock)) {
        NFCLOG_E("mutex for hci transport is released");
    }
exit:
    if (NFC_STATUS_OK != osi_mutex_unlock(&g_hci_rsp_lock)) {
        NFCLOG_E("mutex for hci transport is released");
    }
}

#endif // IS_FEATURE_ON(NCI_FEATURE_HCI)
